package com.example.rpc_core.proxy;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.example.rpc_core.config.RpcConfig;
import com.example.rpc_core.constance.RpcConstant;
import com.example.rpc_core.model.RpcRequestExample;
import com.example.rpc_core.model.RpcResponseExample;
import com.example.rpc_core.RpcApplication;
import com.example.rpc_core.model.ServiceInfo;
import com.example.rpc_core.register.Register;
import com.example.rpc_core.register.RegistryFactory;
import com.example.rpc_core.serializable.Serializable;
import com.example.rpc_core.serializable.SerializableFactory;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.List;

public class ServiceProxy implements InvocationHandler {
    /**
     * 实现动态代理
     *
     * @param proxy  the proxy instance that the method was invoked on
     * @param method the {@code Method} instance corresponding to
     *               the interface method invoked on the proxy instance.  The declaring
     *               class of the {@code Method} object will be the interface that
     *               the method was declared in, which may be a superinterface of the
     *               proxy interface that the proxy class inherits the method through.
     * @param args   an array of objects containing the values of the
     *               arguments passed in the method invocation on the proxy instance,
     *               or {@code null} if interface method takes no arguments.
     *               Arguments of primitive types are wrapped in instances of the
     *               appropriate primitive wrapper class, such as
     *               {@code java.lang.Integer} or {@code java.lang.Boolean}.
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Serializable serializable = SerializableFactory.getSerializable(
                RpcApplication.getRpcConfig().getSerializable());
        // 优先处理Object类的方法
        if (method.getDeclaringClass() == Object.class) {
            try {
                return method.invoke(this, args);  //使用this而不是proxy，避免递归调用
            } catch (Exception e) {
                throw new RuntimeException("Object方法调用失败", e);
            }
        }

        //构建代理对象
        RpcRequestExample rpcRequestExample =
                new RpcRequestExample().builder()
                        .serviceName(method.getDeclaringClass().getName())
                        .args(args)
                        .parameterTypes(method.getParameterTypes())
                        .methodName(method.getName())
                        .build();
        //序列化对象
//        System.out.println("Method declared in: " + method.getDeclaringClass().getName());
        byte[] serialize = serializable.serialize(rpcRequestExample);
//
//        try {
//            HttpResponse response = HttpRequest.post("http://localhost:8081")
//                    .body(serialize)
//                    .execute();
//            byte[] body = response.bodyBytes();
//            RpcResponseExample deserialize = serializable.deserialize(body, RpcResponseExample.class);
//            return deserialize.getData();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
        RpcConfig rpcConfig = RpcApplication.getRpcConfig();
        Register register= RegistryFactory.getRegistry(rpcConfig.getRegistryConfig().getRegistryType());
        ServiceInfo serviceInfo=new ServiceInfo();
        serviceInfo.setServiceName(method.getDeclaringClass().getName());
        serviceInfo.setServiceVersion(RpcConstant.DEFAULT_CONFIG_Version);
        List<ServiceInfo> serviceInfos = register.serviceDiscovery(serviceInfo.getServiceNodeKey());
        if (CollUtil.isEmpty(serviceInfos))  {
            throw new RuntimeException("未找到服务");
        }
        //先取第一个
        ServiceInfo serviceGetInfo = serviceInfos.get(0);
        try (HttpResponse httpResponse = HttpRequest.post(serviceGetInfo.getServiceAddress())
                .body(serialize)
                .execute()) {
            byte[] body = httpResponse.bodyBytes();
            //反序列化
            RpcResponseExample deserialize = serializable.deserialize(body, RpcResponseExample.class);
            return deserialize.getData();
        }
    }
}